package org.oschina.api.comment.dao;

import java.util.Iterator;
import java.util.List;
import org.oschina.Constants;
import org.oschina.api.BaseDAO;
import org.oschina.api.comment.model.Comment;
import org.oschina.api.comment.vo.CommentVo;
import org.oschina.api.user.user.vo.UserVo;
import org.oschina.helper.query.IQueryCacheCallback;
import org.springframework.stereotype.Repository;

@Repository
public class CommentDAO extends BaseDAO {

	private final String findVo="SELECT cm.id,cm.content,cm.major,cm.relevance,cm.floor,cm.catalog,cm.type,cm.author_id as 'author.id',us.username as 'author.username',us.headphoto as 'author.headphoto',cm.quote,cm.quote_count,cm.create_time FROM "+
		Constants.DB_COMMENT+" cm,"+Constants.DB_USER+" us WHERE cm.author_id=us.id";
	
	private final String findVoByType=findVo+" AND cm.type=? ORDER BY cm.create_time DESC LIMIT ?,?";
	/**
	 * 根据类型返回
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	public List<CommentVo> findVoByType(int type,int first,int max)
	{
		return getQueryHelper().query(findVoByType, new Object[]{type,first,max}, CommentVo.class);
	}
	
	/**
	 * 根据类型返回数量
	 * @param type
	 * @return
	 */
	public int getCountByType(int type)
	{
		return (int) getQueryHelper().queryDataSum(new String[]{"type=?"}, new Object[]{type}, CommentVo.class);
	}
	
	/**
	 * 根据ID返回
	 * @param id
	 * @return
	 */
	public CommentVo findVoById(int id)
	{
		CommentVo commentVo=(CommentVo) getCacheHelper().hget(getIdKey(id), CommentVo.class);
		if(commentVo!=null)
			return commentVo;
		
		return _findById(id);
	}
	private final String findById=findVo+" AND cm.id=?";
	private CommentVo _findById(int id)
	{
		return (CommentVo) getQueryHelper().queryForObject(findById, new Object[]{id}, CommentVo.class);
	}
	
	/**
	 * 根据评论ID和类型返回数量
	 * @param commentId
	 * @param type
	 * @return
	 */
	public int getCountByCommentIdAndType(int commentId,int type)
	{
		if(!isNeedCache(commentId))
			return _getCountByCommentIdAndType(commentId,type);
		
		String cache=getCountCacheByCommentId(commentId);
		Integer result=(Integer) getCacheHelper().hget(cache, type, Integer.class);
		if(result==null)
		{
			result=_getCountByCommentIdAndType(commentId,type);
			getCacheHelper().hset(cache,type, result,Constants.TIMEOUT_COMMENT);
		}
		return result;
	}
	private int _getCountByCommentIdAndType(int commentId,int type)
	{
		return (int) getQueryHelper().queryDataSum(new String[]{"major=?","type=?","quote=0"}, new Object[]{commentId,type}, CommentVo.class);
	}
	private void updateCommentCount(int commentId,int type,int count)
	{
		getCacheHelper().hincr(getCountCacheByCommentId(commentId),String.valueOf(type), count);
	}
	private String getCountCacheByCommentId(int id)
	{
		return Constants.CACHE_COMMENT_COUNT+"_"+id;
	}
	
	/**
	 * 根据评论ID和类型返回
	 * @param commentId
	 * @param first
	 * @param max
	 * @return
	 */
	public List<CommentVo> findByCommentIdAndType(final int commentId,final int type,int first,int max)
	{
		if(!isNeedCache(commentId))
			return _findByCommentIdAndType(commentId, type, first, max);
		
		List<CommentVo> result=getQueryHelper().query_cache(getListKey(commentId,type),Constants.TIMEOUT_COMMENT,Constants.MAX_CACHE_COMMENT,
			first,max,CommentVo.class,
			new IQueryCacheCallback()
			{
				@Override
				public List get(int first, int max)
				{
					return _findByCommentIdAndType(commentId, type, first, max);
				}
			}
		);
		
		Iterator<CommentVo> iterator=result.iterator();
		while(iterator.hasNext())
		{
			CommentVo commentVo=iterator.next();
			if(commentVo!=null && commentVo.getType().equals(type))
				cacheData(commentVo);
			else
				iterator.remove();
		}
		return result;
	}
	private final String findByCommentIdAndType=findVo+" AND cm.major=? AND cm.type=? AND cm.quote=0 ORDER BY create_time LIMIT ?,?";
	private List<CommentVo> _findByCommentIdAndType(int commentId,int type,int first,int max)
	{
		return getQueryHelper().query(findByCommentIdAndType, new Object[]{commentId,type,first,max}, CommentVo.class);
	}
	
	/**
	 * 根据评论ID返回层数
	 * @param id
	 * @return
	 */
	public int getMaxFloorByCommentId(int id)
	{
		if(!isNeedCache(id))
			return _getFloorByCommentId(id);
		
		String cache=getFloorCache(id);
		Integer result=(Integer) getCacheHelper().get(cache, Integer.class);
		if(result==null)
		{
			result=_getFloorByCommentId(id);
			getCacheHelper().set(cache, result ,Constants.TIMEOUT_COMMENT);
		}
		return result;
	}
	private int _getFloorByCommentId(int id)
	{
		return (Integer) getQueryHelper().queryForObject("SELECT COUNT(*) FROM "+Constants.DB_COMMENT+" WHERE major=? AND quote=0", new Object[]{id}, Integer.class);
	}
	private void updateFloorCache(int id,int count)
	{
		getCacheHelper().incr(getFloorCache(id), count);
	}
	private String getFloorCache(Object id)
	{
		return getKey(Constants.CACHE_COMMENT_FLOOR,id);
	}
	
	/**
	 * 返回引用
	 * @param quote
	 * @param type
	 * @param first
	 * @param max
	 * @return
	 */
	public List<CommentVo> findVoByQuoteAndType(final int quote,final int type,int first,int max)
	{
		if(!isInCache(quote))
			return _findVoByQuoteAndType(quote,type,first,max);

		List<CommentVo> result=getQueryHelper().query_cache(getQuoteList(quote,type),Constants.TIMEOUT_COMMENT,Constants.MAX_CACHE_COMMENT,
			first,max,CommentVo.class,
			new IQueryCacheCallback()
			{
				@Override
				public List get(int first, int max)
				{
					return _findVoByQuoteAndType(quote,type,first,max);
				}
			}
		);
		
		Iterator<CommentVo> iterator=result.iterator();
		while(iterator.hasNext())
		{
			CommentVo commentVo=iterator.next();
			if(commentVo!=null && commentVo.getType().equals(type))
				cacheData(commentVo);
			else
				iterator.remove();
		}
		return result;
	}
	private final String findByQuoteAndType=findVo+" AND cm.quote=? AND cm.type=? ORDER BY create_time LIMIT ?,?";
	private List<CommentVo> _findVoByQuoteAndType(int quote,int type,int first,int max)
	{
		return getQueryHelper().query(findByQuoteAndType, new Object[]{quote,type,first,max}, CommentVo.class);
	}
	private String getQuoteList(int id,int type)
	{
		return Constants.CACHE_COMMENT_QUOTE_LIST+"_"+id+"_"+type;
	}
	
	/**
	 * 更新类型
	 * @param id
	 * @param type
	 * @return
	 */
	public int updateType(int id,int type)
	{
		CommentVo commentVo=findByCache(id);
		if(commentVo!=null && !commentVo.getType().equals(type))
			getCacheHelper().hset(getIdKey(id), "type", type, Constants.TIMEOUT_COMMENT);
		
		return (int) getQueryHelper().update(new String[]{"type=?"}, new String[]{"id=?"}, new Object[]{type,id},CommentVo.class);
	}
	
	/**
	 * 更新引用数量
	 * @param id
	 * @param count
	 */
	public void updateQuoteCount(int id,int count)
	{
		getCacheHelper().hincr(getIdKey(id),"quote_count",count);
		batchUpdate_queue("UPDATE "+Constants.DB_COMMENT+" SET quote_count=quote_count+? WHERE id=?", new Object[]{count,id});
	}
	
	/**
	 * 编辑
	 * @param comment
	 * @return
	 */
	public int edit(Comment comment)
	{
		updateCache(comment.getId(),new String[]{"content"},new Object[]{comment.getContent()});
		return (int) getQueryHelper().update(new String[]{"content=?"}, new String[]{"id=?"}, new Object[]{comment.getContent(),comment.getId()},CommentVo.class);
	}
	
	/**
	 * 创建
	 * @param comment
	 * @return
	 */
	public Comment create(Comment comment)
	{
		getQueryHelper().insert(new String[]{"id","major","relevance","content","floor","author_id","quote","quote_count","type","catalog","ip","create_time"},
			new Object[]{comment.getId(),comment.getMajor(),comment.getRelevance(),comment.getContent(),comment.getFloor(),comment.getAuthor().getId(),comment.getQuote(),comment.getQuote_count(),comment.getType(),comment.getCatalog(),comment.getIp(),comment.getCreate_time()}
			,CommentVo.class);
		
		if(isNeedCache(comment.getMajor()))
		{
			UserVo author=new UserVo();
			author.setId(comment.getAuthor().getId());
			author.setUsername(comment.getAuthor().getUsername());
			author.setHeadphoto(comment.getAuthor().getHeadphoto());
			CommentVo commentVo=new CommentVo();
			commentVo.setId(comment.getId());
			commentVo.setAuthor(author);
			commentVo.setContent(comment.getContent());
			commentVo.setMajor(comment.getMajor());
			commentVo.setRelevance(comment.getRelevance());
			commentVo.setCreate_time(comment.getCreate_time());
			commentVo.setFloor(comment.getFloor());
			commentVo.setQuote(comment.getQuote());
			commentVo.setQuote_count(comment.getQuote_count());
			commentVo.setType(comment.getType());
			commentVo.setCatalog(comment.getCatalog());

			putCache(commentVo);
			if(comment.getQuote().equals(0))
			{
				updateFloorCache(comment.getMajor(), 1);
				updateCommentCount(comment.getMajor(),comment.getType(), 1);
				getCacheHelper().rpush(getListKey(comment.getMajor(),commentVo.getType()), commentVo.getId(), Constants.TIMEOUT_COMMENT);
			}
			else
			{
				getCacheHelper().rpush(getQuoteList(comment.getQuote(),commentVo.getType()), commentVo.getId(), Constants.TIMEOUT_COMMENT);
			}
		}
		
		return comment;
	}
	
	private boolean isInCache(int id)
	{
		return getCacheHelper().exists(getIdKey(id));
	}
	
	private void putCache(CommentVo comment)
	{
		getCacheHelper().hset(getIdKey(comment.getId()), comment, CommentVo.class, Constants.TIMEOUT_COMMENT);
	}
	
	private CommentVo findByCache(int id)
	{
		return (CommentVo) getCacheHelper().hget(getIdKey(id), CommentVo.class);
	}
	
	private String getListKey(int commentId,int type)
	{
		return Constants.CACHE_COMMENT_LIST+"_"+commentId+"_"+type;
	}
	
	/**
	 * 需要缓存
	 * @param major
	 */
	public void needCache(int major)
	{
		getCacheHelper().hset(Constants.CACHE_COMMENT_NEED, major, true, Constants.TIMEOUT_COMMENT);
	}
	
	/**
	 * 是否需要缓存
	 * @param major
	 * @return
	 */
	private boolean isNeedCache(int major)
	{
		return (getCacheHelper().hget(Constants.CACHE_COMMENT_NEED, major, Object.class)!=null);
	}
	
	private void cacheData(CommentVo commentVo)
	{
	}
	
	private String getIdKey(Object id)
	{
		return getKey(Constants.CACHE_COMMENT,id);
	}
	
	private void updateCache(int id,String fields[],Object values[])
	{
		updateCache(Constants.CACHE_COMMENT,id,fields,values,Constants.TIMEOUT_COMMENT);
	}
}